# import binascii
# import pickle
import string
import random

from ecdsa import SigningKey, SECP256k1

# from block_chain import BlockChain
# from data_bundle import DataBundle
# from network import PeerServer
# from txpool import TxPool
from utils_lib.utils import hash_public_key, base58
from utils_lib.encrypt import get_key, encrypt_rsa, decrypt_rsa, get_key_str_from_obj
from sensor import Sensor

from transaction import *
# from block_header import *
# from block import *


# 节点 Node Class
# 一个节点是指一台参与网络的平等主体
class Node(object):
    # 静态类变量 reputation_threshold 和 reputation 可在此全局修改默认值
    DEFAULT_VALUE_REPUTATION_THRESHOLD = '1'
    DEFAULT_VALUE_REPUTATION = '1'

    VERSION = b'\0'
    CURVE = SECP256k1

    def __init__(self, node_private_key,
                 reputation_threshold=DEFAULT_VALUE_REPUTATION_THRESHOLD, reputation=DEFAULT_VALUE_REPUTATION):

        self._node_private_key = node_private_key
        self._node_public_key = node_private_key.get_verifying_key()

        self._node_address = ''

        _rsa_pub_key, _rsa_pri_key = get_key()
        self.node_rsa_public_key, self.node_rsa_private_key = get_key_str_from_obj(_rsa_pub_key, _rsa_pri_key)  # 加密公私钥

        self.reputation_threshold = reputation_threshold
        self.reputation = reputation

        self.sensor_list = []

        self.data_key_dict = {}  # 对称秘钥字典

    @classmethod
    def generate_node(cls, curve=CURVE):
        """
        generate a new node
        """
        sign_key = SigningKey.generate(curve=curve)
        return cls(sign_key)

    @property
    def node_private_key(self):
        return binascii.hexlify(self._node_private_key.to_string())

    @property
    def raw_node_private_key(self):
        return self._node_private_key

    @property
    def node_public_key(self):
        return binascii.hexlify(self._node_public_key.to_string()).decode()

    @property
    def address(self):
        if not self._node_address:
            _temp_address = self.VERSION + self._hash_node_public_key()
            self._node_address = base58.b58encode_check(_temp_address).decode()
        return self._node_address

    def _hash_node_public_key(self):
        return hash_public_key(self._node_public_key.to_string())

    # obj -> dict
    def serialize(self):
        return self.__dict__

    # dict -> obj
    @classmethod
    def deserialize(cls, node_key_dict):
        _node_private_key = node_key_dict.get('_node_private_key', '')
        _node_public_key = node_key_dict.get('_node_public_key', '')

        _node_address = node_key_dict.get('_node_address', '')

        node_rsa_public_key = node_key_dict.get('node_rsa_public_key', '')
        node_rsa_private_key = node_key_dict.get('node_rsa_private_key', '')

        reputation_threshold = node_key_dict.get('reputation_threshold', '')
        reputation = node_key_dict.get('reputation', '')

        sensor_list = node_key_dict.get('sensor_list', '')
        data_key_dict = node_key_dict.get('data_key_dict', {})

        node_obj = Node(_node_private_key, reputation_threshold, reputation)
        node_obj._node_public_key = _node_public_key
        node_obj._node_address = _node_address
        node_obj.node_rsa_public_key = node_rsa_public_key
        node_obj.node_rsa_private_key = node_rsa_private_key
        node_obj.sensor_list = sensor_list
        node_obj.data_key_dict = data_key_dict

        return node_obj

    # 增加sensor并分配秘钥（公钥和私钥）
    def add_sensor(self, sensor_object: Sensor):
        sensor_object.sensor_private_key = SigningKey.generate(curve=self.CURVE)
        sensor_object.sensor_public_key = sensor_object.sensor_private_key.get_verifying_key()
        self.sensor_list.append(sensor_object)
        return

    # 设置对称加密秘钥 (16bit str) 每次上传数据都使用不同的对称秘钥
    # data_id: <str>
    def generate_node_symmetric_key(self, data_id):
        random_key = ''.join(random.sample(string.ascii_letters + string.digits, 16))
        self.data_key_dict[data_id] = random_key
        return

    # 根据data_id获取对称秘钥
    # return: <str>
    def get_node_symmetric_key(self, data_id):
        return self.data_key_dict[data_id]

